#include <arpa/inet.h>  // 提供网络地址转换函数
#include <errno.h>      // 定义错误码
#include <fcntl.h>      // 文件操作相关函数
#include <netinet/in.h> // 定义网络协议的结构体和函数
#include <pthread.h>    // 引入pthread库
#include <signal.h>     // 提供信号处理函数
#include <stdio.h>      // 标准输入输出
#include <stdlib.h>     // 标准库函数，如exit()
#include <string.h>     // 字符串操作函数
#include <sys/socket.h> // 套接字相关函数
#include <sys/time.h>   // 提供 gettimeofday 函数
#include <sys/types.h>  // 定义数据类型
#include <time.h>       // 时间相关函数
#include <unistd.h>     // 提供POSIX API，如read()、write()

#include "Cache.h"
#include "thpool.h"
#include "epoll_server.h"

#define VERSION 23    // 服务器版本号
#define BUFSIZE 8096  // 缓冲区大小
#define ERROR 42      // 错误日志类型
#define LOG 44        // 普通日志类型
#define FORBIDDEN 403 // HTTP状态码：禁止访问
#define NOTFOUND 404  // HTTP状态码：未找到资源

// 支持的文件扩展名及其对应的MIME类型
struct
{
    char *ext;      // 文件扩展名
    char *filetype; // MIME类型
} extensions[] = {
    {"gif", "image/gif"},
    {"jpg", "image/jpg"},
    {"jpeg", "image/jpeg"},
    {"png", "image/png"},
    {"ico", "image/ico"},
    {"zip", "image/zip"},
    {"gz", "image/gz"},
    {"tar", "image/tar"},
    {"htm", "text/html"},
    {"html", "text/html"},
    {0, 0} // 结束标志
};

// 计时变量，分别记录每个线程池的总时间和任务数量
long total_read_msg_time = 0;
long total_read_file_time = 0;
long total_send_msg_time = 0;
int read_msg_count = 0;
int read_file_count = 0;
int send_msg_count = 0;

Cache *cache; // 缓存

typedef struct
{
    int hit;
    int fd;
    int epollfd;
} webparam;

typedef struct
{
    char filename[BUFSIZE];
    int socket_fd;
    int epollfd;
} filename_msg;

typedef struct
{
    char *file_content;
    int socket_fd;
    int epollfd;
} msg;

// epoll
struct thread_param
{
    int epollfd;                // epoll 类型fd
    struct epoll_event *events; // 事件列表
    int num;                    // 事件列表中的事件数量
    int listenfd;               // 侦听 fd
};
pid_t gettid() { return syscall(SYS_gettid); }
pthread_mutex_t lock;
static int fd_array[FDSIZE]; // 0 表示没有写入；1 表示已经写入
static char *filetype = "text/html";
// 函数声明
int setnonblocking(int fd);
// 创建套接字并进行绑定
int socket_bind(const char *ip, int port);
// I/O 多路复用epoll
void do_epoll(int listenfd);
// 事件处理函数
// void handle_events(int epollfd,struct epoll_event *events,int num,int listenfd);
void *handle_events(void *param);
// 处理接收的连接
void handle_accpet(int epollfd, int listenfd);
// 读处理
int do_read(int epollfd, int fd, char *buf);
// 写处理
void do_write(int epollfd, int fd, char *buf);
// 添加事件
void add_event(int epollfd, int fd, int state);
// 修改事件
void modify_event(int epollfd, int fd, int state);
// 删除事件
void delete_event(int epollfd, int fd, int state);
// 简化哈希表
char *simple_table[HASHSIZE];
int num_table = 0;
pthread_mutex_t simple_table_lock;
// 初始化哈希表
void init_simple_table();
// 得到哈希表中存储的个数
int get_size_simple_table();
// 得到指定项
char *find_item_simple_table(int fd);
// 加入指定项
void add_item_simple_table(int fd, char *buf);
// 删除指定项
void del_item_simple_table(int fd);
// 释放整个表
void free_simple_table();
// 1 successful; 0 failed
int check_simple_table();
static int singleOmulti = 0; // 多线程模式为1，单线程模式为0，默认为 0

// epoll end

pthread_mutex_t filename_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;

// 线程池初始化
threadpool read_msg_pool;
threadpool read_file_pool;
threadpool send_msg_pool;

void *read_msg(void *data);
void *read_file(void *data);
void *send_msg(void *data);

// 信号处理函数，用于切换调度算法
void sigint_handler_for_shift(int signum)
{
    SwitchToOther(cache);
}

// 信号处理函数，用于捕捉 SIGINT 并打印时间统计
void sigint_handler(int signum)
{
    printf("\nCaught signal %d: Stats for I/O operations\n", signum);
    printf("Total Requests: %d | %d | %d\n", read_msg_count, read_file_count, send_msg_count);
    if (read_msg_count > 0)
        printf("Average read_msg time: %ld us\n", total_read_msg_time / read_msg_count);
    if (read_file_count > 0)
        printf("Average read_file time: %ld us\n", total_read_file_time / read_file_count);
    if (send_msg_count > 0)
        printf("Average send_msg time: %ld us\n", total_send_msg_time / send_msg_count);

    exit(0); // 退出程序
}

// 计算两个时间点之间的时间差（以微秒为单位）
long calculate_time_diff(struct timespec start, struct timespec end)
{
    long diff_sec = end.tv_sec - start.tv_sec;    // 秒部分差值
    long diff_nsec = end.tv_nsec - start.tv_nsec; // 纳秒部分差值
    return diff_sec * 1000000 + diff_nsec / 1000; // 转换为微秒
}

// 定义互斥锁用于保护日志文件
pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;

// 日志记录
void logger(int type, const char *s1, const char *s2, int socket_fd)
{
    int fd;
    char logbuffer[BUFSIZE * 2];
    char timebuffer[64];

    struct timeval tv;
    gettimeofday(&tv, NULL);

    struct tm *tm_info = localtime(&tv.tv_sec);
    strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S", tm_info);

    char full_timebuffer[256];
    snprintf(full_timebuffer, sizeof(full_timebuffer), "[%s.%03ld]", timebuffer, tv.tv_usec / 1000);

    switch (type)
    {
    case ERROR:
        snprintf(logbuffer, sizeof(logbuffer), "%s [ERROR] %s:%s Errno=%d exiting pid=%d",
                 full_timebuffer, s1, s2, errno, getpid());
        break;
    case FORBIDDEN:
        if (write(socket_fd,
                  "HTTP/1.1 403 Forbidden\nContent-Length: 185\nConnection: "
                  "close\nContent-Type: text/html\n\n"
                  "<html><head>\n<title>403 "
                  "Forbidden</title>\n</head><body>\n<h1>Forbidden</h1>\n"
                  "The requested URL, file type or operation is not allowed on this simple "
                  "static file webserver.\n"
                  "</body></html>\n",
                  271) < 0)
        {
            perror("Failed to send 403 Forbidden response");
        }
        snprintf(logbuffer, sizeof(logbuffer), "%s [FORBIDDEN] %s:%s", full_timebuffer, s1, s2);
        break;
    case NOTFOUND:
        if (write(socket_fd,
                  "HTTP/1.1 404 Not Found\nContent-Length: 136\nConnection: "
                  "close\nContent-Type: text/html\n\n"
                  "<html><head>\n<title>404 Not Found</title>\n</head><body>\n<h1>Not "
                  "Found</h1>\n"
                  "The requested URL was not found on this server.\n</body></html>\n",
                  224) < 0)
        {
            perror("Failed to send 404 Not Found response");
        }
        snprintf(logbuffer, sizeof(logbuffer), "%s [NOT FOUND] %s:%s", full_timebuffer, s1, s2);
        break;
    case LOG:
        snprintf(logbuffer, sizeof(logbuffer), "%s [INFO] %s:%s:%d", full_timebuffer, s1, s2,
                 socket_fd);
        break;
    }

    // 加锁保护日志文件写入
    pthread_mutex_lock(&log_mutex);
    if ((fd = open("webserver.log", O_CREAT | O_WRONLY | O_APPEND, 0644)) >= 0)
    {
        if (write(fd, logbuffer, strlen(logbuffer)) < 0)
        {
            perror("Failed to write log to file");
        }
        if (write(fd, "\n", 1) < 0)
        {
            perror("Failed to write newline to log file");
        }
        close(fd);
    }
    else
    {
        perror("Failed to open log file");
    }

    pthread_mutex_unlock(&log_mutex);
}

//------反序列化并推送给read_file_pool
// 读取客户端请求消息并加入filename队列
void *read_msg(void *data)
{
    int fd;
    int hit;
    int epollfd;
    char buffer[BUFSIZE + 1];
    webparam *param = (webparam *)data;
    fd = param->fd;
    hit = param->hit;
    epollfd = param->epollfd;

    //-----记录时间
    struct timespec start, end;
    clock_gettime(CLOCK_MONOTONIC, &start);

    int ret = do_read(epollfd, fd, buffer);
    if (ret <= 0)
    {
        logger(FORBIDDEN, "Failed to read browser request", "", fd);
        close(fd);   // 关闭套接字
        free(param); // 释放内存
        return NULL;
    }

    // int ret = read(fd, buffer, BUFSIZE); // 读取客户端请求
    // if (ret <= 0)
    // {
    //     logger(FORBIDDEN, "Failed to read browser request", "", fd);
    //     close(fd);   // 关闭套接字
    //     free(param); // 释放内存
    //     return NULL;
    // }

    //----反序列化
    // 清除换行符和回车符
    for (int i = 0; i < ret; i++)
    {
        if (buffer[i] == '\r' || buffer[i] == '\n')
            buffer[i] = '*';
    }

    // 检查是否为GET请求
    if (strncmp(buffer, "GET ", 4))
    {
        logger(FORBIDDEN, "Only simple GET operation supported", buffer, fd);
        close(fd);   // 关闭套接字
        free(param); // 释放内存
        return NULL;
    }

    // 截取文件路径
    int i;
    for (i = 4; i < BUFSIZE; i++)
    {
        if (buffer[i] == ' ')
        {
            buffer[i] = 0;
            break;
        }
    }

    // 检查路径是否合法
    for (int j = 0; j < i - 1; j++)
    {
        if (buffer[j] == '.' && buffer[j + 1] == '.')
        {
            logger(FORBIDDEN, "Parent directory (..) path names not supported", buffer, fd);
            close(fd);   // 关闭套接字
            free(param); // 释放内存
            return NULL;
        }
    }

    // 默认返回 index.html
    if (!strncmp(&buffer[0], "GET /\0", 6))
    {
        strcpy(buffer, "GET /index.html");
    }

    // 文件类型解析
    char *fstr = NULL;
    int buflen = strlen(buffer);
    for (i = 0; extensions[i].ext != 0; i++)
    {
        int len = strlen(extensions[i].ext);
        if (!strncmp(&buffer[buflen - len], extensions[i].ext, len))
        {
            fstr = extensions[i].filetype;
            break;
        }
    }

    if (fstr == NULL)
    {
        logger(FORBIDDEN, "File extension type not supported", buffer, fd);
        close(fd);   // 关闭套接字
        free(param); // 释放内存
        return NULL;
    }

    // 动态分配filename_msg结构体并填充数据
    filename_msg *filename_msg_param = malloc(sizeof(filename_msg));
    strcpy(filename_msg_param->filename, buffer + 5); // 从GET之后开始的文件名
    filename_msg_param->socket_fd = fd;
    filename_msg_param->epollfd = epollfd;
    // 将任务加入read_file线程池
    thpool_add_work(read_file_pool, read_file, filename_msg_param);
    logger(LOG, "read_file added to thpool", filename_msg_param->filename, fd);

    free(param); // 释放read_msg中使用的内存

    clock_gettime(CLOCK_MONOTONIC, &end);
    long duration = calculate_time_diff(start, end);
    total_read_msg_time += duration; // 累加read_msg的时间
    read_msg_count++;                // 统计read_msg操作次数

    return NULL;
}

//------从cache中读取数据并推送给send_msg_pool
// 从filename队列读取文件并加入msg队列
void *read_file(void *data)
{
    printf("read_file start!!!!!!!!!\r\n\n");

    filename_msg *filename_msg_param = (filename_msg *)data; // 接收从read_msg传递过来的filename_msg结构体指针

    // 动态分配msg结构体并填充数据
    // msg *file_msg = malloc(sizeof(msg));
    // file_msg->socket_fd = filename_msg_param->socket_fd;

    // 从cache中读取文件内容
    printf("get_from_cache start!!!!!!!!!\r\n");
    char *file_content = get_from_cache(cache, filename_msg_param->filename);
    printf("get_from_cache success!!!!!!!!!\r\n\n");

    if (file_content != NULL)
    {
        // 存入哈希表   手动设置写就绪
        add_item_simple_table(filename_msg_param->socket_fd, file_content);
        modify_event(filename_msg_param->epollfd, filename_msg_param->socket_fd, EPOLLOUT | EPOLLET);
        logger(LOG, "File found in cache", filename_msg_param->filename, filename_msg_param->socket_fd);
    }
    else
    {
        logger(LOG, "read_file read NULL digital", filename_msg_param->filename, filename_msg_param->socket_fd);
        return NULL;
    }

    // 将任务加入send_msg线程池
    // thpool_add_work(send_msg_pool, send_msg, file_msg);
    // logger(LOG, "send_msg added to thpool", file_msg->file_content, file_msg->socket_fd);
    printf("read_file end!!!!!!!!\r\n\n");
    return NULL;
}

// 从msg队列发送文件内容到客户端
void *send_msg(void *data)
{
    msg *file_msg = (msg *)data; // 接收从read_file传递过来的msg结构体指针

    struct timespec start, end;
    clock_gettime(CLOCK_MONOTONIC, &start);

    // 发送HTTP响应头
    char header[BUFSIZE];
    int len = strlen(file_msg->file_content);
    sprintf(header,
            "HTTP/1.1 200 OK\nServer: nweb/%d.0\nContent-Length: %d\nConnection: "
            "close\nContent-Type: text/html\n\n",
            VERSION, len);

    // 向客户端发送响应头
    if (write(file_msg->socket_fd, header, strlen(header)) < 0)
    {
        logger(ERROR, "Failed to write HTTP header", "", file_msg->socket_fd);
        close(file_msg->socket_fd);
        // free(file_msg->file_content);  // 释放内存
        free(file_msg); // 释放内存
        return NULL;
    }

    // 向客户端发送文件内容
    // if (write(file_msg->socket_fd, file_msg->file_content, len) < 0)
    // {
    //     logger(ERROR, "Failed to write file content", "", file_msg->socket_fd);
    // }

    do_write(file_msg->epollfd, file_msg->socket_fd, file_msg->file_content);

    clock_gettime(CLOCK_MONOTONIC, &end);
    long duration = calculate_time_diff(start, end);
    total_send_msg_time += duration; // 记录文件写入时间
    send_msg_count++;                // 统计send_msg操作次数

    // 默认一次全部写完，所以从哈希表中删除相关项
    printf("free item:%d\n\n", file_msg->socket_fd);

    printf("start del_item_simple_table!!!\n");
    del_item_simple_table(file_msg->socket_fd);
    printf("end del_item_simple_table!!!\n");

    // 关闭套接字
    close(file_msg->socket_fd);
    // free(file_msg->file_content);  // 释放内存
    free(file_msg); // 释放内存
    return NULL;
}

// epoll
//  设置文件描述符为非阻塞
int setnonblocking(int fd)
{
    int op;
    op = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
    return op;
}
int socket_bind(const char *ip, int port)
{
    int listenfd;
    struct sockaddr_in servaddr;
    int sock_op = 1;
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1)
    {
        perror("socket error:");
        exit(1);
    }
    // 设置侦听端口为重用状态
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &sock_op, sizeof(sock_op));
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &servaddr.sin_addr);
    servaddr.sin_port = htons(port);
    if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
    {
        perror("bind error: ");
        exit(1);
    }
    return listenfd;
}
// 0 --- invalide ; 1 - valid
int is_validevent(int epollfd, struct epoll_event *events, int num)
{
    int inval_num = 0;
    int i;
    for (i = 0; i < num; i++)
    {
        if ((events[i].events & EPOLLRDHUP) || (events[i].events & EPOLLERR))
        {
            // unregister the events for fd
            if (events[i].events & EPOLLIN)
                delete_event(epollfd, events[i].data.fd, EPOLLIN | EPOLLET);
            else if (events[i].events & EPOLLOUT)
                delete_event(epollfd, events[i].data.fd, EPOLLOUT | EPOLLET);
            close(events[i].data.fd);
            if (find_item_simple_table(events[i].data.fd) != NULL)
            {
                del_item_simple_table(events[i].data.fd);
            }
            inval_num++;
        }
    }
    if (inval_num == num)
        return 0;
    else
        return 1;
}
void do_epoll(int listenfd)
{
    int epollfd;
    struct epoll_event events[EPOLLEVENTS];
    int ret;
    struct thread_param *param;
    int epoll_wait_num = 0;
    // 创建一个描述符
    epollfd = epoll_create(FDSIZE);
    // 添加侦听描述符事件
    add_event(epollfd, listenfd, EPOLLIN | EPOLLET);
    printf("epoll server start to listen\n");
    for (;;)
    {
        // 获取已经准备好的描述符事件
        ret = epoll_wait(epollfd, events, EPOLLEVENTS, TIMEOUT);
        printf("--------------epoll_wait_num %d -------------\n", ++epoll_wait_num);
        if (ret > 0 && is_validevent(epollfd, events, ret) == 1)
        {
            // 创建一个线程来处理epoll 返回的监控事件
            param = malloc(sizeof(struct thread_param));
            param->epollfd = epollfd;
            param->events = events;
            param->num = ret;
            param->listenfd = listenfd;
            pthread_t ntid;
            if (singleOmulti == 1)
            {
                pthread_create(&ntid, NULL, handle_events, (void *)param);
            }
            else
            {
                handle_events((void *)param);
            }
        }
        else if (ret == 0)
        {
            // time out
            printf("time out, but need not to restart, continue to loop\n");
            // int size = get_size_simple_table()
            // printf("time out, the size of simple_table is %d \n", size)
            // if(size > 0 || !check_simple_table()){
            // printf("the size of simple_table is not zero or the num_table is not equal to the
            // number of items \n "); printf("so, maybe some error in epoll. \n ") break
            // }
        }
        else if (ret == -1)
        {
            if (errno == EINTR)
                continue;
            // 发生错误 errno
            printf("epoll finds error %d\n", errno);
            break;
        }
    }
    close(epollfd);
}
int num_handle_events = 0;
// void* handle_events(int epollfd,struct epoll_event *events,int num,int listenfd, char *buf)
void *handle_events(void *th_param)
{
    int i;
    int fd;
    struct thread_param *param;
    printf("************** the number of handle_events is %d ************************\n",
           ++num_handle_events);
    param = (struct thread_param *)th_param;
    // 选好遍历
    for (i = 0; i < param->num; i++)
    {
        fd = param->events[i].data.fd;
        // 根据描述符的类型和事件类型进行处理
        if ((fd == param->listenfd) && (param->events[i].events & EPOLLIN))
            handle_accpet(param->epollfd, param->listenfd);
        else if (param->events[i].events & EPOLLIN)
        {
            webparam *tparam = malloc(sizeof(webparam));
            tparam->hit = num_handle_events; // 记录请求的次数
            tparam->fd = fd;
            tparam->epollfd = param->epollfd;

            // 将任务加入read_msg线程池
            thpool_add_work(read_msg_pool, read_msg, tparam);
        }
        else if (param->events[i].events & EPOLLOUT)
        {
            // 从哈希表中获得从客户端读出的数据
            int haswrite = 0;
            if (singleOmulti == 1)
            {
                // 线程锁
                pthread_mutex_lock(&lock);
                if (fd_array[fd] == 0)
                {
                    // 设置，写属性
                    fd_array[fd] = 1;
                }
                else
                {
                    haswrite = 1;
                }
                pthread_mutex_unlock(&lock);
            }
            if (haswrite == 0)
            {
                char *data = find_item_simple_table(fd);
                if (data != NULL)
                {
                    msg *file_msg = malloc(sizeof(msg));
                    file_msg->socket_fd = fd;
                    file_msg->epollfd = param->epollfd;
                    file_msg->file_content = data;
                    // 将任务加入send_msg线程池
                    thpool_add_work(send_msg_pool, send_msg, file_msg);
                    logger(LOG, "send_msg added to thpool", file_msg->file_content, file_msg->socket_fd);
                }
                // recycle the fd;
                fd_array[fd] = 0;
            }
        }
    }
    printf("thread %d exit\n", gettid());
    free(param);
}
void handle_accpet(int epollfd, int listenfd)
{
    int clildfd;
    struct sockaddr_in clildaddr;
    socklen_t clildaddrlen;
    clildfd = accept(listenfd, (struct sockaddr *)&clildaddr, &clildaddrlen);
    if (clildfd == -1)
        perror("accpet error:");
    else
    {
        printf("accept a new client fd= %d: %s:%d\n", clildfd, inet_ntoa(clildaddr.sin_addr),
               clildaddr.sin_port);
        // 设置为非阻塞
        setnonblocking(clildfd);
        // 添加一个客户描述符和事件
        add_event(epollfd, clildfd, EPOLLIN | EPOLLET);
    }
}
int do_read(int epollfd, int fd, char *buf)
{
    int nread;
    /*
    此处默认一次将客户端数据全部读出来，如果客户端传输数据过大，则需将下面的read 操作加入循环
    中，例如
    while((nread=read(fd,buf,MAXSIZE)) >= 0)
    */
    nread = read(fd, buf, BUFSIZE);
    // while((nread=read(fd,buf,MAXSIZE)) >= 0);

    if (nread < 0)
    {
        perror("read error:\n");
        if (errno == EAGAIN || errno == EWOULDBLOCK)
        {
            perror("EAGAIN or EWOULDBLOCK\n");
        }
        else
        {
            fprintf(stderr, "client %d read error\n", fd);
            delete_event(epollfd, fd, EPOLLIN | EPOLLET);
            close(fd);
        }
    }
    else if (nread == 0)
    {
        fprintf(stderr, "client %d close.\n", fd);
        delete_event(epollfd, fd, EPOLLIN | EPOLLET);
        close(fd);
    }
    else
    {
        printf("read message is : %s \n", buf);
        // 修改描述符对应的事件，由读改为写，以便使用同一个fd 向客户端写数据
        // modify_event(epollfd, fd, EPOLLOUT | EPOLLET);
    }
    return nread;
}
void do_write(int epollfd, int fd, char *buf)
{
    /*
    将write 嵌入循环结构中，一直发送剩余数据，直到将所有数据发送完为止
    */
    int success = 1;
    int writepos = 0;
    int nleft = strlen(buf);
    while (nleft > 0)
    {
        int nwrite = 0;
        nwrite = write(fd, buf + writepos, nleft);
        if (nwrite == -1)
        {
            if (errno == errno == EWOULDBLOCK || errno == EAGAIN)
            {
                nwrite = 0;
            }
            else
            {
                perror("write error:\n");
                delete_event(epollfd, fd, EPOLLOUT | EPOLLET);
                close(fd);
                del_item_simple_table(fd);
                success = 0;
                break;
            }
        }
        else
        {
            nleft -= nwrite;
            writepos += nwrite;
        }
    }
    if (success == 1)
    {
        printf("write %d successfully \n", fd);
        modify_event(epollfd, fd, EPOLLIN | EPOLLET);
    }
}
void add_event(int epollfd, int fd, int state)
{
    struct epoll_event ev;
    ev.events = state;
    ev.data.fd = fd;
    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
}
void delete_event(int epollfd, int fd, int state)
{
    struct epoll_event ev;
    ev.events = state;
    ev.data.fd = fd;
    // epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,&ev);
    epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL);
}
void modify_event(int epollfd, int fd, int state)
{
    struct epoll_event ev;
    ev.events = state;
    ev.data.fd = fd;
    epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev);
}
void init_simple_table()
{
    int i;
    num_table = 0;
    if (pthread_mutex_init(&simple_table_lock, NULL) != 0)
    {
        printf("\n mutex init failed \n");
        exit(1);
    }
    for (i = 0; i < HASHSIZE; ++i)
    {
        simple_table[i] = NULL;
    }
}
char *find_item_simple_table(int fd) { return simple_table[fd]; }
int get_size_simple_table() { return num_table; }
void add_item_simple_table(int fd, char *buf)
{
    pthread_mutex_lock(&simple_table_lock);
    if (find_item_simple_table(fd) == NULL)
    {
        // 不存在 key
        ++num_table;
    }
    simple_table[fd] = buf;
    pthread_mutex_unlock(&simple_table_lock);
}
void del_item_simple_table(int fd)
{
    pthread_mutex_lock(&simple_table_lock);
    if (simple_table[fd] == NULL)
    {
        // 不存在key
        // 避免多次稀释相同数据项
        pthread_mutex_lock(&simple_table_lock);
        return;
    }
    else
    {
        if (simple_table[fd] == NULL)
        {
            pthread_mutex_lock(&simple_table_lock);
            return;
        }
        char *all = simple_table[fd];
        simple_table[fd] = NULL;

        if (all == NULL)
        {
            pthread_mutex_lock(&simple_table_lock);
            return;
        }
        free(all);
        --num_table;
    }
    pthread_mutex_unlock(&simple_table_lock);
}
void free_simple_table()
{
    int i;
    pthread_mutex_lock(&simple_table_lock);
    for (i = 0; i < HASHSIZE; i++)
    {
        if (simple_table[i] != NULL)
        {
            free(simple_table[i]);
        }
    }
    num_table = 0;
    pthread_mutex_unlock(&simple_table_lock);
}
// 返回值为1，表示成功;返回值为0，表示失败
int check_simple_table()
{
    int i;
    int num = 0;
    for (i = 0; i < HASHSIZE; ++i)
    {
        if (simple_table[i] != NULL)
        {
            ++num;
        }
    }
    if (num != num_table)
        return 0;
    else
        return 1;
}
// epoll end

int main(int argc, char **argv)
{
    int port, listenfd, socketfd, hit;
    socklen_t length;
    static struct sockaddr_in cli_addr;  // 客户端地址
    static struct sockaddr_in serv_addr; // 服务器地址

    // 注册SIGINT信号的处理函数
    signal(SIGINT, sigint_handler);
    signal(SIGTSTP, sigint_handler_for_shift);

    // 检查命令行参数是否正确
    if (argc < 4 || argc > 4 || !strcmp(argv[1], "-?"))
    {
        printf("Usage: %s <Port> <Directory> <mode>\n", argv[0]);
        exit(0);
    }

    if (chdir(argv[2]) == -1)
    {
        perror("Failed to change directory");
        exit(4);
    }

    // epoll接入
    if (argc == 4)
    {
        if (strcmp(argv[3], "multi") == 0)
            singleOmulti = 1;
        else if (strcmp(argv[3], "single") == 0)
            singleOmulti = 0;
        else
        {
            printf("please inputs parameter: multi or single\n");
        }
    }

    if (pthread_mutex_init(&lock, NULL) != 0)
    {
        printf("\n mutex init failed \n");
        return 1;
    }

    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("Socket creation failed");
        exit(1);
    }

    port = atoi(argv[1]);
    if (port < 1 || port > 60000)
    {
        fprintf(stderr, "Invalid port number: %d\n", port);
        exit(1);
    }

    // 设置服务器监听套接字
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(port);
    if (bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        perror("bind failed");
        exit(1);
    }

    if (listen(listenfd, 64) < 0)
    {
        perror("listen failed");
        exit(1);
    }

    // 初始化缓存，最大缓存大小为 5
    cache = create_cache(5);

    // 初始化线程池
    read_msg_pool = thpool_init(5);
    read_file_pool = thpool_init(5);
    send_msg_pool = thpool_init(5);

    while (1)
    {
        // 初始化哈希表
        init_simple_table();
        // 初始化fd_array
        int i;
        for (i = 0; i < FDSIZE; i++)
        {
            fd_array[i] = 0;
        }
        printf("start the server\n");

        // listenfd = socket_bind(IPADDRESS, port);

        listen(listenfd, LISTENQ);
        // 设置listenfd 为非阻塞
        setnonblocking(listenfd);
        do_epoll(listenfd);
        // 销毁哈希表
        free_simple_table();
        close(listenfd);
        printf("close the server and restart the server\n");
    }

    thpool_wait(read_msg_pool);
    thpool_wait(read_file_pool);
    thpool_wait(send_msg_pool);

    // 销毁线程池
    thpool_destroy(read_msg_pool);
    thpool_destroy(read_file_pool);
    thpool_destroy(send_msg_pool);

    // 销毁缓存
    destroy_cache(cache);

    return 0;
}
